import { Quaternion, Vector3 } from "@babylonjs/core/Maths/math.vector";
import { CombineRig } from "./combine-rig";
import { AnimationFrame } from 'babylon-lib/animation/animation-frame';


class CombineRigGroup {

    public readonly rigs: Array<CombineRig> = [];

    private _aniReq = {};
    private _tPosition = new Vector3();
    private _tScaling = new Vector3();

    constructor() { }

    public addRig(rig: CombineRig): void {
        if (this.rigs.indexOf(rig) < 0) {
            rig.localUpdate = false;
            this.rigs.push(rig);
        }
    }

    public removeRig(rig: CombineRig): void {
        const index = this.rigs.indexOf(rig);
        if (index >= 0) {
            rig.localUpdate = true;
            this.rigs.splice(index, 1);
        }
    }

    public play(loop: boolean): void {
        this.rigs.forEach(rig => {
            rig.setAnimateState('play', loop);
        });
        this.start();
    }

    public stop(): void {
        this.rigs.forEach(rig => {
            rig.setAnimateState('stop', true);
        });
        AnimationFrame.cancel(this._aniReq);
    }

    public pause(): void {
        this.rigs.forEach(rig => {
            rig.setAnimateState('pause', true);
        });
        AnimationFrame.cancel(this._aniReq);
    }

    private start(): void {
        if (AnimationFrame.isRunning(this._aniReq)) return;
        AnimationFrame.request(() => {
            this.update();
        }, 16, 200, this._aniReq);
    }

    private update(): void {
        const ws: number[] = [];
        const tp = this._tPosition;
        const ts = this._tScaling;
        if (this.rigs.length) {
            ws.length = 0;
            let tol = 0;
            for (let i = 0; i < this.rigs.length; i++) {
                const rig = this.rigs[i];
                ws.push(rig.weight);
                tol += rig.weight;
            }

            for (let n = 0; n < this.rigs.length; n++) {
                const rig = this.rigs[n];
                const sr = (tol ? ws[n] / tol : 1);
                for (let i = 0; i < rig.animationMap.length; i++) {
                    const aniNode = rig.animationMap[i];
                    tp.copyFrom(aniNode.position).scaleInPlace(sr);
                    ts.copyFrom(aniNode.scaling).scaleInPlace(sr);
                    rig.skeletonMaps.forEach(skeletonMap => {
                        const boneNode = skeletonMap[i];
                        if (boneNode) {
                            if (!n) {
                                boneNode.position.copyFrom(tp);
                                boneNode.scaling.copyFrom(ts);
                            } else {
                                boneNode.position.addInPlace(tp);
                                boneNode.scaling.addInPlace(ts);
                            }
                            Quaternion.SlerpToRef(boneNode.rotationQuaternion!, aniNode.rotationQuaternion!, sr, boneNode.rotationQuaternion!);
                        }
                    });
                }
            }
        }
    }
}


export { CombineRigGroup };